home *** CD-ROM | disk | FTP | other *** search
/ Aminet 51 / Aminet 51 (2002)(GTI - Schatztruhe)[!][Oct 2002].iso / Aminet / util / misc / ReportPlus.lha / reportplus / source / f10.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-08-23  |  70.9 KB  |  1,967 lines

  1. #include <exec/types.h>
  2. #include <exec/memory.h>
  3. #include <intuition/intuition.h>
  4. #include <intuition/gadgetclass.h>
  5. #include <libraries/gadtools.h>
  6. #include <dos/dos.h>
  7. #include <dos/dostags.h>
  8. #include <dos/dosextens.h>
  9. #include <dos/exall.h>
  10. #include <dos/datetime.h>
  11. #include <graphics/gfx.h>
  12.  
  13. #include <clib/alib_protos.h>
  14. #include <clib/intuition_protos.h>
  15. #include <clib/graphics_protos.h>
  16. #include <clib/dos_protos.h>
  17. #include <clib/gadtools_protos.h>
  18. #include <clib/exec_protos.h>
  19.  
  20. #include <ctype.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include "rp.h"
  24.  
  25. #define ALL_REACTION_CLASSES
  26. #include <reaction/reaction.h>
  27.  
  28. #define FILESMODE_BUILD   0
  29. #define FILESMODE_COMPARE 1
  30.  
  31. MODULE void updatefiles(void);
  32. MODULE void stage1(void);
  33. MODULE void files_work(void);         // for stage1()
  34. MODULE void stage2(void);
  35. MODULE void dobuffer(ULONG whichpen); // for stage2()
  36. MODULE void stopping(STRPTR status);
  37. MODULE void files_updatelog(void);
  38. MODULE void updateghosting(void);
  39. MODULE void gadgetstate(ABOOL starting);
  40. MODULE void AddFilesNode(struct List* ListPtr, STRPTR pathname, STRPTR datetime, STRPTR version, STRPTR size);
  41. MODULE void FreeFilesNodes(struct List* ListPtr);
  42. MODULE void addslash(void);
  43.  
  44. IMPORT ABOOL                ram;
  45. IMPORT SBYTE                page;
  46. IMPORT TEXT                 IOBuffer[LONGESTFIELD + 1],
  47.                             aslresult[PATHNAMEFIELD + 1];
  48. IMPORT ULONG                increment;
  49. IMPORT struct Screen*       ScreenPtr;
  50. IMPORT struct ExAllData*    EADataPtr;
  51. IMPORT struct Menu*         MenuPtr;
  52. IMPORT Object*              WinObject[FUNCTIONS + 1];
  53. IMPORT struct Library      *ButtonBase,
  54.                            *CheckBoxBase,
  55.                            *ChooserBase,
  56.                            *IconBase,
  57.                            *LabelBase,
  58.                            *LayoutBase,
  59.                            *ListBrowserBase,
  60.                            *StringBase,
  61.                            *WindowBase;
  62. IMPORT struct TextAttr      Topaz8;
  63.  
  64. AGLOBAL struct Gadget*      files_gadgets[GIDS_10 + 1];
  65.  
  66. MODULE BOOL                 outerghost       = FALSE,
  67.                             innerghost       = FALSE;
  68. MODULE struct List          DirList,         // list of NameNodes (internal use)
  69.                             FoundList,       // list of FilesNodes
  70.                             ResultList,      // listbrowser list
  71.                             EmptyResultList, // listbrowser list
  72.                             SnapshotList;    // list of NameNodes (internal use)
  73. MODULE ULONG                filesfound,
  74.                             status           = STATUS_READY;
  75.  
  76. MODULE struct FilesNode
  77. {   struct Node Node;
  78.     ABOOL       matched;
  79.     TEXT        pathname[256 + 1],
  80.                 datetime[18 + 1],
  81.                 version[256 + 1],
  82.                 size[13 + 1];
  83. };
  84. MODULE struct
  85. {   ULONG show[4], // anything we want to use GetAttr() with must be ULONG
  86.           log, checkversion, checkdatetime, checksize,
  87.           entries, mode;
  88.     TEXT  logfile[PATHNAMEFIELD + 1],
  89.           snapshot[PATHNAMEFIELD + 1],
  90.           basepath[PATHNAMEFIELD + 1];
  91. } files =
  92. {   TRUE, TRUE, TRUE, TRUE,
  93.     TRUE, TRUE, TRUE, TRUE,
  94.     0, FILESMODE_COMPARE,
  95.     "RAM:ReportPlus.log", "PROGDIR:ReportPlus.snapshot", "SYS:"
  96. };
  97. MODULE  BPTR           TheHandle             = NULL;
  98. MODULE  TEXT           activedir[PATHNAMEFIELD + 1],
  99.                        activefile[PATHNAMEFIELD + 1],
  100.                        lockstring[PATHNAMEFIELD + 1],
  101.                        liststring[7][PATHNAMEFIELD + 1];
  102.  
  103. #define COLUMN_PATHNAME   0
  104. #define COLUMN_DATETIME   1
  105. #define COLUMN_SIZE       2
  106. #define COLUMN_VERSION    3
  107. #define COLUMN_SSDATETIME 4
  108. #define COLUMN_SSSIZE     5
  109. #define COLUMN_SSVERSION  6
  110.  
  111. MODULE struct ColumnInfo ResultColumnInfo[] =
  112. { { 36,            // WORD   ci_Width
  113.     "Pathname",    // STRPTR ci_Title
  114.     0,             // ULONG  ci_Flags
  115.   },
  116.   { 10,
  117.     "Found Date/Time",
  118.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  119.           to the right border of the relevant column). */
  120.   },
  121.   { 7,
  122.     "Found Size",
  123.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  124.           to the right border of the relevant column). */
  125.   },
  126.   { 15,
  127.     "Found Version",
  128.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  129.           to the right border of the relevant column). */
  130.   },
  131.   { 10,
  132.     "Exp. Date/Time",
  133.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  134.           to the right border of the relevant column). */
  135.   },
  136.   { 7,
  137.     "Exp. Size",
  138.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  139.           to the right border of the relevant column). */
  140.   },
  141.   { 15,
  142.     "Expected Version",
  143.     0, /* Last column must not have CIF_DRAGGABLE set (CIF_DRAGGABLE applies
  144.           to the right border of the relevant column). */
  145.   },
  146.   { -1, (STRPTR) ~0, -1
  147. } };
  148.  
  149. MODULE STRPTR ModeOptions[3] =
  150. {   (STRPTR) "Make snapshot of base path",
  151.     (STRPTR) "Compare base path against snapshot",
  152.     NULL
  153. };
  154.  
  155. MODULE struct
  156. {   ULONG red, green, blue, pennumber;
  157. } penn[5] =
  158. {   {0x55555555, 0xFFFFFFFF, 0x55555555, -1}, // green  (OK)        .
  159.     {0xFFFFFFFF, 0x88888888, 0x00000000, -1}, // orange (changed)   !
  160.     {0x55555555, 0xFFFFFFFF, 0xFFFFFFFF, -1}, // cyan   (3rd-party) +
  161.     {0xFFFFFFFF, 0x44444444, 0x44444444, -1}, // red    (missing)   -
  162.     {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, -1}, // white  (built)    n/a
  163. };
  164.  
  165. // from rp.c
  166. IMPORT SBYTE               page;
  167. IMPORT struct Window*      MainWindowPtr;
  168. IMPORT TEXT                weekdaystring[LEN_DATSTRING],
  169.                            datestring[LEN_DATSTRING],
  170.                            timestring[LEN_DATSTRING];
  171.  
  172. AGLOBAL void files1(void)
  173. {   struct Hook Hook10Struct;
  174.  
  175.     updateghosting();
  176.  
  177.     InitHook(&Hook10Struct, Hook10Func, NULL);
  178.  
  179.     /* Create the window object. */
  180.     lockscreen();
  181.     if (!(WinObject[10] =
  182.     NewObject
  183.     (
  184.     WINDOW_GetClass(), NULL,
  185.     WA_PubScreen,                 ScreenPtr,
  186.     WA_ScreenTitle,               "Report+",
  187.     WA_Title,                     "Report+: System Files Report",
  188.     WA_Activate,                  TRUE,
  189.     WA_DepthGadget,               TRUE,
  190.     WA_DragBar,                   TRUE,
  191.     WA_CloseGadget,               TRUE,
  192.     WA_SizeGadget,                TRUE,
  193.     WA_IDCMP,                     IDCMP_RAWKEY,
  194.     WINDOW_IDCMPHook,             &Hook10Struct,
  195.     WINDOW_IDCMPHookBits,         IDCMP_RAWKEY,
  196.     WINDOW_MenuStrip,             MenuPtr,
  197.     WINDOW_Position,              WPOS_CENTERSCREEN,
  198.     WINDOW_ParentGroup,           files_gadgets[GID_10_LY1] =
  199.                                   NewObject(LAYOUT_GetClass(), NULL,
  200.         // root-layout
  201.         LAYOUT_Orientation,       LAYOUT_ORIENT_VERT,
  202.         LAYOUT_SpaceOuter,        TRUE,
  203.         LAYOUT_DeferLayout,       TRUE,
  204.         LAYOUT_AddChild,          NewObject(LAYOUT_GetClass(), NULL,
  205.             // layout
  206.             LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
  207.             LAYOUT_SpaceOuter,    TRUE,
  208.             LAYOUT_VertAlignment, LALIGN_CENTER,
  209.             LAYOUT_HorizAlignment,LALIGN_CENTER,
  210.             LAYOUT_BevelStyle,    BVS_NONE,
  211.             LAYOUT_AddChild,
  212.             NewObject
  213.             (   LAYOUT_GetClass(),    NULL,
  214.                 LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
  215.                 LAYOUT_SpaceOuter,    TRUE,
  216.                 LAYOUT_VertAlignment, LALIGN_CENTER,
  217.                 LAYOUT_HorizAlignment,LALIGN_LEFT,
  218.                 LAYOUT_BevelStyle,    BVS_NONE,
  219.                 LAYOUT_AddChild,
  220.                 NewObject
  221.                 (   LAYOUT_GetClass(),    NULL,
  222.                     LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
  223.                     LAYOUT_SpaceOuter,    TRUE,
  224.                     LAYOUT_VertAlignment, LALIGN_CENTER,
  225.                     LAYOUT_HorizAlignment,LALIGN_LEFT,
  226.                     LAYOUT_BevelStyle,    BVS_FIELD,
  227.                     LAYOUT_AddImage,
  228.                     NewObject
  229.                     (   LABEL_GetClass(),     NULL,
  230.                         LABEL_Text,           "Show:",
  231.                     TAG_END),
  232.                     CHILD_WeightedHeight,     0,
  233.                     LAYOUT_AddChild,          files_gadgets[GID_10_CB1] =
  234.                     NewObject
  235.                     (   CHECKBOX_GetClass(),  NULL,
  236.                         GA_ID,                GID_10_CB1,
  237.                         GA_RelVerify,         TRUE,
  238.                         CHECKBOX_BackgroundPen, penn[0].pennumber,
  239.                         GA_Text,              "_OK (.)",
  240.                         GA_Selected,          (BOOL) files.show[0],
  241.                     TAG_END),
  242.                     CHILD_WeightedHeight,     0,
  243.                     LAYOUT_AddChild,          files_gadgets[GID_10_CB2] =
  244.                     NewObject
  245.                     (   CHECKBOX_GetClass(),  NULL,
  246.                         GA_ID,                GID_10_CB2,
  247.                         GA_RelVerify,         TRUE,
  248.                         CHECKBOX_BackgroundPen, penn[1].pennumber,
  249.                         GA_Text,              "_Changed (!)",
  250.                         GA_Selected,          (BOOL) files.show[1],
  251.                         TAG_END
  252.                     ),
  253.                     CHILD_WeightedHeight,     0,
  254.                     LAYOUT_AddChild,          files_gadgets[GID_10_CB3] =
  255.                     NewObject
  256.                     (   CHECKBOX_GetClass(),  NULL,
  257.                         GA_ID,                GID_10_CB3,
  258.                         GA_RelVerify,         TRUE,
  259.                         CHECKBOX_BackgroundPen, penn[2].pennumber,
  260.                         GA_Text,              "_3rd-party (+)",
  261.                         GA_Selected,          (BOOL) files.show[2],
  262.                         TAG_END
  263.                     ),
  264.                     CHILD_WeightedHeight,     0,
  265.                     LAYOUT_AddChild,          files_gadgets[GID_10_CB4] =
  266.                     NewObject
  267.                     (   CHECKBOX_GetClass(),  NULL,
  268.                         GA_ID,                GID_10_CB4,
  269.                         GA_RelVerify,         TRUE,
  270.                         CHECKBOX_BackgroundPen, penn[3].pennumber,
  271.                         GA_Text,              "_Missing (-)",
  272.                         GA_Selected,          (BOOL) files.show[3],
  273.                     TAG_END),
  274.                     CHILD_WeightedHeight,     0,
  275.                 TAG_END),
  276.                 CHILD_WeightedHeight,         0,
  277.                 LAYOUT_AddChild,
  278.                 NewObject
  279.                 (   LAYOUT_GetClass(),    NULL,
  280.                     LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
  281.                     LAYOUT_SpaceOuter,    TRUE,
  282.                     LAYOUT_VertAlignment, LALIGN_CENTER,
  283.                     LAYOUT_HorizAlignment,LALIGN_LEFT,
  284.                     LAYOUT_BevelStyle,    BVS_FIELD,
  285.                     LAYOUT_AddImage,
  286.                     NewObject
  287.                     (   LABEL_GetClass(),     NULL,
  288.                         LABEL_Text,           "Compare:",
  289.                     TAG_END),
  290.                     CHILD_WeightedHeight,     0,
  291.  
  292.  
  293.                     LAYOUT_AddChild,      files_gadgets[GID_10_CB8] =
  294.                     NewObject
  295.                     (   CHECKBOX_GetClass(), NULL,
  296.                         GA_ID,            GID_10_CB8,
  297.                         GA_RelVerify,     TRUE,
  298.                         GA_Text,          "Si_zes",
  299.                         GA_Selected,      (BOOL) files.checksize,
  300.                         GA_Disabled,      outerghost,
  301.                     TAG_END),
  302.                     CHILD_WeightedWidth,  0,
  303.                     LAYOUT_AddChild,      files_gadgets[GID_10_CB6] =
  304.                     NewObject
  305.                     (   CHECKBOX_GetClass(), NULL,
  306.                         GA_ID,            GID_10_CB6,
  307.                         GA_RelVerify,     TRUE,
  308.                         GA_Text,          "_Dates/times",
  309.                         GA_Selected,      (BOOL) files.checkdatetime,
  310.                         GA_Disabled,      outerghost,
  311.                     TAG_END),
  312.                     CHILD_WeightedWidth,  0,
  313.                     LAYOUT_AddChild,      files_gadgets[GID_10_CB5] =
  314.                     NewObject
  315.                     (   CHECKBOX_GetClass(), NULL,
  316.                         GA_ID,            GID_10_CB5,
  317.                         GA_RelVerify,     TRUE,
  318.                         GA_Text,          "_Versions",
  319.                         GA_Selected,      (BOOL) files.checkversion,
  320.                         GA_Disabled,      outerghost,
  321.                     TAG_END),
  322.                     CHILD_WeightedWidth,  0,
  323.                 TAG_END),
  324.                 CHILD_WeightedHeight,         0,
  325.             TAG_END),
  326.             CHILD_WeightedWidth,      0,
  327.             LAYOUT_AddChild,
  328.             NewObject
  329.             (   LAYOUT_GetClass(),    NULL,
  330.                 LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
  331.                 LAYOUT_SpaceOuter,    TRUE,
  332.                 LAYOUT_VertAlignment, LALIGN_TOP,
  333.                 LAYOUT_HorizAlignment,LALIGN_CENTER,
  334.                 LAYOUT_BevelStyle,    BVS_NONE,
  335.                 LAYOUT_ShrinkWrap,    TRUE,
  336.                 LAYOUT_AddChild,
  337.                 NewObject
  338.                 (   LAYOUT_GetClass(),    NULL,
  339.                     LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
  340.                     LAYOUT_SpaceOuter,    TRUE,
  341.                     LAYOUT_VertAlignment, LALIGN_CENTER,
  342.                     LAYOUT_HorizAlignment,LALIGN_CENTER,
  343.                     LAYOUT_BevelStyle,    BVS_FIELD,
  344.                     LAYOUT_AddChild,
  345.                     NewObject
  346.                     (   LAYOUT_GetClass(),    NULL,
  347.                         LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
  348.                         LAYOUT_SpaceOuter,    TRUE,
  349.                         LAYOUT_VertAlignment, LALIGN_CENTER,
  350.                         LAYOUT_HorizAlignment,LALIGN_CENTER,
  351.                         LAYOUT_BevelStyle,    BVS_FIELD,
  352.                         LAYOUT_ShrinkWrap,    TRUE,
  353.                         LAYOUT_AddChild,
  354.                         NewObject
  355.                         (   LAYOUT_GetClass(),    NULL,
  356.                             LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
  357.                             LAYOUT_SpaceOuter,    TRUE,
  358.                             LAYOUT_VertAlignment, LALIGN_TOP,
  359.                             LAYOUT_HorizAlignment,LALIGN_LEFT,
  360.                             LAYOUT_BevelStyle,    BVS_NONE,
  361.                             LAYOUT_ShrinkWrap,    TRUE,
  362.                             LAYOUT_AddImage,
  363.                             NewObject
  364.                             (   LABEL_GetClass(), NULL,
  365.                                 LABEL_Text,       "Mod_e:",
  366.                             TAG_END),
  367.                             CHILD_WeightedWidth,  0,
  368.                         TAG_END),
  369.                         CHILD_WeightedHeight,     0,
  370.                         LAYOUT_AddChild,          files_gadgets[GID_10_RA1] =
  371.                         NewObject
  372.                         (   RADIOBUTTON_GetClass(),NULL,
  373.                             GA_ID,                GID_10_RA1,
  374.                             GA_RelVerify,         TRUE,
  375.                             GA_Text,              ModeOptions,
  376.                             RADIOBUTTON_Selected, (WORD) files.mode,
  377.                         TAG_END),
  378.                     TAG_END),
  379.                     LAYOUT_AddChild,
  380.                     NewObject
  381.                     (   LAYOUT_GetClass(),    NULL,
  382.                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
  383.                         LAYOUT_SpaceOuter,    TRUE,
  384.                         LAYOUT_VertAlignment, LALIGN_CENTER,
  385.                         LAYOUT_HorizAlignment,LALIGN_CENTER,
  386.                         LAYOUT_BevelStyle,    BVS_NONE,
  387.                         LAYOUT_ShrinkWrap,    TRUE,
  388.                         LAYOUT_AddImage,
  389.                         NewObject
  390.                         (   LABEL_GetClass(), NULL,
  391.                             LABEL_Text,       "_Snapshot pathname:",
  392.                         TAG_END),
  393.                         CHILD_WeightedWidth,  0,
  394.                         LAYOUT_AddChild,      files_gadgets[GID_10_ST2] =
  395.                         NewObject
  396.                         (   STRING_GetClass(),NULL,
  397.                             GA_ID,            GID_10_ST2,
  398.                             GA_TabCycle,      TRUE,
  399.                             GA_RelVerify,     TRUE,
  400.                             STRINGA_TextVal,  files.snapshot,
  401.                             STRINGA_MaxChars, PATHNAMEFIELD,
  402.                             STRINGA_MinVisible,10,
  403.                         TAG_END),
  404.                         CHILD_WeightedWidth,  100,
  405.                         LAYOUT_AddChild,      files_gadgets[GID_10_BU4] =
  406.                         NewObject
  407.                         (   NULL,             "button.gadget",
  408.                             GA_ID,            GID_10_BU4,
  409.                             GA_RelVerify,     TRUE,
  410.                             BUTTON_AutoButton,BAG_POPFILE,
  411.                         TAG_END),
  412.                         CHILD_WeightedWidth,  0,
  413.                     TAG_END),
  414.                     CHILD_WeightedHeight,     0,
  415.                     LAYOUT_AddChild,
  416.                     NewObject
  417.                     (   LAYOUT_GetClass(),    NULL,
  418.                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
  419.                         LAYOUT_SpaceOuter,    TRUE,
  420.                         LAYOUT_VertAlignment, LALIGN_CENTER,
  421.                         LAYOUT_HorizAlignment,LALIGN_CENTER,
  422.                         LAYOUT_BevelStyle,    BVS_NONE,
  423.                         LAYOUT_ShrinkWrap,    TRUE,
  424.                         LAYOUT_AddImage,
  425.                         NewObject
  426.                         (   LABEL_GetClass(), NULL,
  427.                             LABEL_Text,       "_Base path:",
  428.                         TAG_END),
  429.                         CHILD_WeightedWidth,  0,
  430.                         LAYOUT_AddChild,      files_gadgets[GID_10_ST3] =
  431.                         NewObject
  432.                         (   STRING_GetClass(),NULL,
  433.                             GA_ID,            GID_10_ST3,
  434.                             GA_TabCycle,      TRUE,
  435.                             GA_RelVerify,     TRUE,
  436.                             STRINGA_TextVal,  files.basepath,
  437.                             STRINGA_MinVisible,10,
  438.                             STRINGA_MaxChars, PATHNAMEFIELD,
  439.                         TAG_END),
  440.                         CHILD_WeightedWidth,  100,
  441.                         LAYOUT_AddChild,      files_gadgets[GID_10_BU5] =
  442.                         NewObject
  443.                         (   NULL,             "button.gadget",
  444.                             GA_ID,            GID_10_BU5,
  445.                             GA_RelVerify,     TRUE,
  446.                             BUTTON_AutoButton,BAG_POPFILE,
  447.                         TAG_END),
  448.                         CHILD_WeightedWidth,  0,
  449.                     TAG_END),
  450.                     CHILD_WeightedHeight,     0,
  451.                     LAYOUT_AddChild,          files_gadgets[GID_10_FG1] =
  452.                     NewObject
  453.                     (   FUELGAUGE_GetClass(), NULL,
  454.                         GA_ID,                GID_10_FG1,
  455.                         GA_Text,              "Ready.",
  456.                         FUELGAUGE_Level,      0,
  457.                         FUELGAUGE_Percent,    FALSE,
  458.                         FUELGAUGE_Justification,FGJ_CENTER,
  459.                     TAG_END),
  460.                     CHILD_WeightedHeight,     0,
  461.                     LAYOUT_AddChild,
  462.                     NewObject
  463.                     (   LAYOUT_GetClass(),    NULL,
  464.                         LAYOUT_Orientation,   LAYOUT_ORIENT_HORIZ,
  465.                         LAYOUT_SpaceOuter,    TRUE,
  466.                         LAYOUT_VertAlignment, LALIGN_CENTER,
  467.                         LAYOUT_HorizAlignment,LALIGN_CENTER,
  468.                         LAYOUT_BevelStyle,    BVS_NONE,
  469.                         LAYOUT_AddChild,      files_gadgets[GID_10_BU2] =
  470.                         NewObject
  471.                         (   NULL,             "button.gadget",
  472.                             GA_ID,            GID_10_BU2,
  473.                             GA_RelVerify,     TRUE,
  474.                             GA_Text,          "_Update",
  475.                         TAG_END),
  476.                         CHILD_WeightedWidth,  50,
  477.                         LAYOUT_AddChild,      files_gadgets[GID_10_BU3] =
  478.                         NewObject
  479.                         (   NULL,             "button.gadget",
  480.                             GA_ID,            GID_10_BU3,
  481.                             GA_RelVerify,     TRUE,
  482.                             GA_Text,          "Stop",
  483.                             GA_Disabled,      TRUE,
  484.                         TAG_END),
  485.                         CHILD_WeightedWidth,  50,
  486.                     TAG_END),
  487.                     CHILD_WeightedHeight,     0,
  488.                 TAG_END),
  489.                 CHILD_WeightedHeight,         0,
  490.                 LAYOUT_AddChild,
  491.                 NewObject
  492.                 (   LAYOUT_GetClass(),    NULL,
  493.                     LAYOUT_Orientation,   LAYOUT_ORIENT_VERT,
  494.                     LAYOUT_SpaceOuter,    TRUE,
  495.                     LAYOUT_VertAlignment, LALIGN_CENTER,
  496.                     LAYOUT_HorizAlignment,LALIGN_CENTER,
  497.                     LAYOUT_BevelStyle,    BVS_FIELD,
  498.                     LAYOUT_ShrinkWrap,    TRUE,
  499.                     LAYOUT_AddChild,
  500.                     NewObject
  501.                     (   LAYOUT_GetClass(),       NULL,
  502.                         LAYOUT_Orientation,      LAYOUT_ORIENT_HORIZ,
  503.                         LAYOUT_SpaceOuter,       TRUE,
  504.                         LAYOUT_VertAlignment,    LALIGN_CENTER,
  505.                         LAYOUT_HorizAlignment,   LALIGN_CENTER,
  506.                         LAYOUT_BevelStyle,       BVS_NONE,
  507.                         LAYOUT_ShrinkWrap,       TRUE,
  508.                         LAYOUT_AddChild,         files_gadgets[GID_10_CB7] =
  509.                         NewObject
  510.                         (   CHECKBOX_GetClass(), NULL,
  511.                             GA_ID,               GID_10_CB7,
  512.                             GA_RelVerify,        TRUE,
  513.                             GA_Text,             "_Log to:",
  514.                             GA_Selected,         (BOOL) files.log,
  515.                             GA_Disabled,         outerghost,
  516.                         TAG_END),
  517.                         CHILD_WeightedWidth,     0,
  518.                         LAYOUT_AddChild,         files_gadgets[GID_10_ST1] =
  519.                         NewObject
  520.                         (   STRING_GetClass(),   NULL,
  521.                             GA_ID,               GID_10_ST1,
  522.                             GA_TabCycle,         TRUE,
  523.                             GA_RelVerify,        TRUE,
  524.                             STRINGA_TextVal,     files.logfile,
  525.                             STRINGA_MinVisible,  10,
  526.                             STRINGA_MaxChars,    PATHNAMEFIELD,
  527.                             GA_Disabled,         innerghost,
  528.                         TAG_END),
  529.                         LAYOUT_AddChild,      files_gadgets[GID_10_BU1] =
  530.                         NewObject
  531.                         (   NULL,             "button.gadget",
  532.                             GA_ID,            GID_10_BU1,
  533.                             GA_RelVerify,     TRUE,
  534.                             BUTTON_AutoButton,BAG_POPFILE,
  535.                             GA_Disabled,      innerghost,
  536.                         TAG_END),
  537.                         CHILD_WeightedWidth,  0,
  538.                     TAG_END),
  539.                     CHILD_WeightedHeight, 0,
  540.                 TAG_END),
  541.                 CHILD_WeightedHeight,     0,
  542.             TAG_END),
  543.             CHILD_WeightedHeight,         0,
  544.         TAG_END),
  545.         CHILD_WeightedHeight,         0,
  546.         LAYOUT_AddChild,              files_gadgets[GID_10_LB1] =
  547.         NewObject
  548.         (   LISTBROWSER_GetClass(),   NULL,
  549.             GA_ID,                    GID_10_LB1,
  550.             GA_ReadOnly,              TRUE,
  551.             GA_TextAttr,              &Topaz8,
  552.             LISTBROWSER_Labels,       (ULONG) &EmptyResultList,
  553.             LISTBROWSER_ColumnInfo,   (ULONG) &ResultColumnInfo,
  554.             LISTBROWSER_ColumnTitles, TRUE,
  555.             LISTBROWSER_HorizontalProp,TRUE,
  556.             LISTBROWSER_VirtualWidth, 620 + 620 + 310,
  557.             LISTBROWSER_MinVisible,   6,
  558.         TAG_END),
  559.         CHILD_WeightedHeight,         100,
  560.         CHILD_MinHeight,              128,
  561.     TAG_END),
  562.     TAG_END
  563.     )))
  564.     {   rq("Can't create ReAction object(s)!");
  565.     }
  566.     unlockscreen();
  567.     openwindow();
  568.     ActivateLayoutGadget(files_gadgets[GID_10_LY1], MainWindowPtr, NULL, (Object) files_gadgets[GID_10_ST2]);
  569.  
  570.     loop();
  571.  
  572.     closewindow();
  573.     files_exit();
  574. }
  575.  
  576. MODULE void updatefiles(void)
  577. {   STRPTR stringptr;
  578.  
  579.     /* Most gadgets are ghosted during the operation. Then their ghosting
  580.     status returns to normal (not necessarily unghosted).
  581.  
  582.         0: Gadget handling.
  583.         1: Set up lists, do the directory examination.
  584.            (For each `source' directory in the `queue', before doing it
  585.            we check for a break. `Break opportunity 1'.)
  586.     At this point we have an empty DirList, and a full FoundList, and an
  587.     empty ResultList.
  588.         2: Create the ResultList.
  589.            (For each `source' file in the `queue', before doing it we
  590.            check for a break. `Break opportunity 2'.)
  591.         3: Show results.
  592.  
  593.        DirList: an Exec list ( NameNodes) of directories found, awaiting examination.
  594.      FoundList: an Exec list (FilesNodes) of files found, awaiting processing.
  595.   SnapshotList: an Exec list (FilesNodes) of files in the snapshot file.
  596.     ResultList: a listbrowser list of files found, for display.
  597.  
  598.     Apparently the way strings work is that you get told an address where
  599.     the string is stored. This is apparently a pointer into system memory;
  600.     it doesn't need explicit allocation/deallocation by our appliprog. */
  601.  
  602.     if (!(GetAttr
  603.     (   STRINGA_TextVal, files_gadgets[GID_10_ST1], (ULONG *) &stringptr
  604.     )))
  605.     {   rq("Unsupported inquiry!"); // should never happen
  606.     }
  607.     strcpy(files.logfile, stringptr);
  608.  
  609.     if (!(GetAttr
  610.     (   STRINGA_TextVal, files_gadgets[GID_10_ST2], (ULONG *) &stringptr
  611.     )))
  612.     {   rq("Unsupported inquiry!"); // should never happen
  613.     }
  614.     strcpy(files.snapshot, stringptr);
  615.  
  616.     if (!(GetAttr
  617.     (   STRINGA_TextVal, files_gadgets[GID_10_ST3], (ULONG *) &stringptr
  618.     )))
  619.     {   rq("Unsupported inquiry!"); // should never happen
  620.     }
  621.     strcpy(files.basepath, stringptr);
  622.     addslash();
  623.  
  624.     gadgetstate(TRUE);
  625.  
  626.     SetGadgetAttrs
  627.     (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  628.         FUELGAUGE_Min,   0,
  629.         FUELGAUGE_Max,   100,
  630.         FUELGAUGE_Level, 8,
  631.         GA_Text,         "Reading from volume...",
  632.         TAG_END
  633.     ); // we don't know how many files in advance...
  634.  
  635.     SetGadgetAttrs
  636.     (   files_gadgets[GID_10_LB1], MainWindowPtr, NULL,
  637.         LISTBROWSER_Labels, NULL,
  638.         TAG_END
  639.     );
  640.     SetGadgetAttrs
  641.     (   files_gadgets[GID_10_LB1], MainWindowPtr, NULL,
  642.         LISTBROWSER_Labels, (ULONG) &EmptyResultList,
  643.         TAG_END
  644.     );
  645.     if ((ResultList.lh_Head)->ln_Succ) // if the list is non-empty
  646.     {   clearreactionlist(&ResultList);
  647.     }
  648.     filesfound = 0;
  649.  
  650.     status = STATUS_BUSY;
  651.  
  652.     stage1(); // calls stage2() itself if appropriate
  653.  
  654.     status = STATUS_READY;
  655.  
  656.     gadgetstate(FALSE);
  657.     SetGadgetAttrs
  658.     (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  659.         FUELGAUGE_Min,   0,
  660.         FUELGAUGE_Max,   100,
  661.         FUELGAUGE_Level, 0,
  662.         GA_Text,         "Ready.",
  663.         TAG_END
  664.     );
  665.     SetGadgetAttrs
  666.     (   files_gadgets[GID_10_LB1], MainWindowPtr, NULL,
  667.         LISTBROWSER_Labels, NULL,
  668.         TAG_END
  669.     );
  670.  
  671.     if ((ResultList.lh_Head)->ln_Succ) // if the list is non-empty
  672.     {   SetGadgetAttrs
  673.         (   files_gadgets[GID_10_LB1], MainWindowPtr, NULL,
  674.             LISTBROWSER_Labels, (ULONG) &ResultList,
  675.             TAG_END
  676.         );
  677.     } else
  678.     {   SetGadgetAttrs
  679.         (   files_gadgets[GID_10_LB1], MainWindowPtr, NULL,
  680.             LISTBROWSER_Labels, (ULONG) &EmptyResultList,
  681.             TAG_END
  682.         );
  683. }   }
  684.  
  685. MODULE void stage1(void)
  686. {   struct NameNode* NameNodePtr;
  687.  
  688.     // Initialize lists
  689.     NewList(&FoundList);
  690.     NewList(&DirList);
  691.     NewList(&ResultList);
  692.     NewList(&SnapshotList);
  693.     AddNameToTail(&DirList, "");
  694.  
  695.     // Pop all the directories from the work stack, and send them one
  696.     // at a time to files_work() for processing.
  697.     while ((DirList.lh_Head)->ln_Succ) // while the list is non-empty
  698.     {   if (ra_checkbreak() == 1) // we don't yet support completely quitting
  699.         {   status = STATUS_STOPPING;
  700.             stopping("Stopping...");
  701.             FreeNameNodes(&DirList);
  702.             FreeFilesNodes(&FoundList);
  703.             return;
  704.         }
  705.  
  706.         /* detach a node from the DirList, copy its path to activedir,
  707.         free the node, and then call files_work(). */
  708.  
  709.         if (!(NameNodePtr = (struct NameNode *) RemTail(&DirList)))
  710.         {   rq("RemTail() failed (list is empty!)"); // this should never happen
  711.         }
  712.         strcpy(activedir, NameNodePtr->nn_Data);
  713.         FreeMem(NameNodePtr, sizeof(struct NameNode));
  714.  
  715.         files_work(); // service routine
  716.     }
  717.  
  718.     /* Now we have a list of all relevant files.
  719.  
  720.     DirList will be empty.
  721.     FoundList will be 'full' (unless the user aborted, or nothing was found).
  722.     ResultList will be empty.
  723.     SnapshotList will be empty. */
  724.  
  725.     stage2();
  726. }
  727.  
  728. MODULE void stage2(void)
  729. {   ABOOL                 matched;
  730.     ULONG                 filesdone = 0,
  731.                           i, j, sizeval,
  732.                           length, snapshots;
  733.     struct FilesNode     *FoundNodePtr,
  734.                          *SnapshotNodePtr;
  735.     TEXT                  filename[PATHNAMEFIELD + 1],
  736.                           pathname[PATHNAMEFIELD + 1],
  737.                           datetime[18 + 1],
  738.                           version[VLONGFIELD + 1],
  739.                           size[13 + 1];
  740.     struct FileInfoBlock* FIBPtr;
  741.     STRPTR                MemoryPtr;
  742.  
  743. /*  We now have the list of all files found.
  744.  
  745.    *1: Check versions of found files.
  746.     2: Read the snapshot file into memory.
  747.     3: Parse the snapshot file into a list of SnapshotNodes.
  748.     4: Open logfile and write logfile header.
  749.    *5: Check each found node against each snapshot node.
  750.     6: Decide missing files.
  751.  
  752.    * means the operation can be aborted at this point.
  753.  
  754. 1. Check versions of found files. ------------------------------------- */
  755.  
  756.     if (files.mode == FILESMODE_BUILD || files.checkversion)
  757.     {   SetGadgetAttrs
  758.         (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  759.             FUELGAUGE_Min,   0,
  760.             FUELGAUGE_Max,   100,
  761.             FUELGAUGE_Level, 16,
  762.             GA_Text,         "Checking versions...",
  763.             TAG_END
  764.         );
  765.  
  766.         if ((FoundList.lh_Head)->ln_Succ) // if the list is non-empty
  767.         {   for
  768.             (   FoundNodePtr = FoundList.lh_Head;
  769.                 FoundNodePtr->Node.ln_Succ;
  770.                 FoundNodePtr = FoundNodePtr->Node.ln_Succ
  771.             )
  772.             {   if (ra_checkbreak() == 1)
  773.                 {   status = STATUS_STOPPING;
  774.                     stopping("Stopping...");
  775.                     FreeFilesNodes(&FoundList);
  776.                     return;
  777.                 }
  778.                 // check that file is not an icon
  779.                 length = strlen(FoundNodePtr->pathname);
  780.                 if (length < 5 || stricmp(&(FoundNodePtr->pathname[length - 5]), ".info"))
  781.                 {   strcpy(pathname, files.basepath);
  782.                     if (!(AddPart(pathname, FoundNodePtr->pathname, PATHNAMEFIELD)))
  783.                     {   rq("AddPart() failed!");
  784.                     }
  785.                     getversion(pathname, FoundNodePtr->version);
  786.                 } else
  787.                 {   strcpy(FoundNodePtr->version, "n/a");
  788.     }   }   }   }
  789.  
  790. // 2. Read the snapshot file into memory. --------------------------------
  791.  
  792.     if (files.mode == FILESMODE_BUILD)
  793.     {   if (!(TheHandle = (BPTR) Open(files.snapshot, MODE_NEWFILE)))
  794.         {   rq("Can't open snapshot file for writing!");
  795.     }   }
  796.     else
  797.     {   assert(files.mode == FILESMODE_COMPARE);
  798.  
  799.         SetGadgetAttrs
  800.         (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  801.             FUELGAUGE_Min,   0,
  802.             FUELGAUGE_Max,   100,
  803.             FUELGAUGE_Level, 24,
  804.             GA_Text,         "Reading snapshot file...",
  805.             TAG_END
  806.         );
  807.  
  808.         if (!(TheHandle = (BPTR) Lock(files.snapshot, ACCESS_READ)))
  809.         {   rq("Can't lock snapshot file!");
  810.         }
  811.         if (!(FIBPtr    = AllocDosObject(DOS_FIB, NULL)))
  812.         {   UnLock(TheHandle);
  813.             TheHandle = NULL;
  814.             rq("Can't allocate DOS object!");
  815.         }
  816.         if (!(Examine(TheHandle, FIBPtr)))
  817.         {   FreeDosObject(DOS_FIB, FIBPtr);
  818.             FIBPtr = NULL;
  819.             UnLock(TheHandle);
  820.             TheHandle = NULL;
  821.             rq("Can't examine snapshot file!");
  822.         }
  823.         sizeval = FIBPtr->fib_Size;
  824.         comma(sizeval, size);
  825.         stcl_d(size, sizeval);
  826.         FreeDosObject(DOS_FIB, FIBPtr);
  827.         FIBPtr = NULL;
  828.         UnLock(TheHandle);
  829.         TheHandle = NULL;
  830.  
  831.         // Open the snapshot file, read it into memory, then close it.
  832.         if (!(TheHandle = (BPTR) Open(files.snapshot, MODE_OLDFILE)))
  833.         {   rq("Can't open snapshot file for reading!");
  834.         }
  835.         if (!(MemoryPtr = AllocVec(sizeval, NULL)))
  836.         {   rq("Out of memory!");
  837.         }
  838.         if (Read(TheHandle, MemoryPtr, sizeval) != sizeval)
  839.         {   rq("Can't read from snapshot file!");
  840.         }
  841.         Close(TheHandle);
  842.         TheHandle = NULL;
  843.  
  844. // 3. Parse the snapshot file into a list of SnapshotNodes. --------------
  845.  
  846.         i         =
  847.         snapshots = 0;
  848.  
  849.         do
  850.         {   j = 0;
  851.             while (*(MemoryPtr + i) != LF)
  852.             {   pathname[j] = *(MemoryPtr + i);
  853.                 i++;
  854.                 j++;
  855.             }
  856.             pathname[j] = 0;
  857.             i++;
  858.  
  859.             j = 0;
  860.             while (*(MemoryPtr + i) != LF)
  861.             {   datetime[j] = *(MemoryPtr + i);
  862.                 i++;
  863.                 j++;
  864.             }
  865.             datetime[j] = 0;
  866.             i++;
  867.  
  868.             j = 0;
  869.             while (*(MemoryPtr + i) != LF)
  870.             {   version[j] = *(MemoryPtr + i);
  871.                 i++;
  872.                 j++;
  873.             }
  874.             version[j] = 0;
  875.             i++;
  876.  
  877.             j = 0;
  878.             while (*(MemoryPtr + i) != LF)
  879.             {   size[j] = *(MemoryPtr + i);
  880.                 i++;
  881.                 j++;
  882.             }
  883.             size[j] = 0;
  884.             i++;
  885.             AddFilesNode(&SnapshotList, pathname, datetime, version, size);
  886.  
  887.             snapshots++;
  888.         } while (i < sizeval);
  889.         FreeVec(MemoryPtr);
  890.  
  891. // 4. Open logfile and write logfile header. -----------------------------
  892.  
  893.         if (files.log)
  894.         {   if (!(TheHandle = (BPTR) Open(files.logfile, MODE_READWRITE)))
  895.             {   rq("Can't open logfile for appending!");
  896.             }
  897.             Seek(TheHandle, 0, OFFSET_END);
  898.  
  899.             strcpy(IOBuffer, files.basepath);
  900.             strcat(IOBuffer, " files as at ");
  901.             getdate();
  902.             strcat(IOBuffer, timestring);
  903.             strcat(IOBuffer, " on ");
  904.             strcat(IOBuffer, weekdaystring);
  905.             strcat(IOBuffer, " ");
  906.             strcat(IOBuffer, datestring);
  907.             strcat(IOBuffer, ":\n\n");
  908.             if (Write(TheHandle, IOBuffer, strlen(IOBuffer)) != strlen(IOBuffer))
  909.             {   rq("Can't append to logfile!");
  910.     }   }   }
  911.  
  912. /* 5. Check each found node against each snapshot node. ------------------
  913.  
  914. We go through FoundList destructively, ie. freeing each node after we
  915. have used it.
  916.  
  917. For each file found, we check it against each snapshot node. If it doesn't
  918. match any, it's third-party. */
  919.  
  920.     if (files.mode == FILESMODE_COMPARE)
  921.     {   SetGadgetAttrs
  922.         (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  923.             FUELGAUGE_Min,   0,
  924.             FUELGAUGE_Max,   filesfound * 3,
  925.             FUELGAUGE_Level, filesfound,
  926.             GA_Text,         "Comparing...",
  927.             TAG_END
  928.         );
  929.     } else
  930.     {   assert(files.mode == FILESMODE_BUILD);
  931.         SetGadgetAttrs
  932.         (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  933.             FUELGAUGE_Min,   0,
  934.             FUELGAUGE_Max,   filesfound * 3,
  935.             FUELGAUGE_Level, filesfound,
  936.             GA_Text,         "Writing snapshot file...",
  937.             TAG_END
  938.         );
  939.     }
  940.  
  941.     while ((FoundList.lh_Head)->ln_Succ) // while the list is non-empty
  942.     {   if (ra_checkbreak() == 1)
  943.         {   status = STATUS_STOPPING;
  944.             stopping("Stopping...");
  945.             if (files.mode == FILESMODE_BUILD || files.log)
  946.             {   strcpy(IOBuffer, "Aborted by user!");
  947.                 if (Write(TheHandle, IOBuffer, strlen(IOBuffer)) != strlen(IOBuffer))
  948.                 {   if (files.mode == FILESMODE_COMPARE)
  949.                     {   rq("Can't append to logfile!");
  950.                     } else
  951.                     {   assert(files.mode == FILESMODE_BUILD);
  952.                         rq("Can't write to snapshot file!");
  953.                 }   }
  954.                 Close(TheHandle); // Close() doesn't return an error code
  955.                 TheHandle = NULL;
  956.             }
  957.             FreeFilesNodes(&FoundList);
  958.             FreeFilesNodes(&SnapshotList);
  959.             return;
  960.         }
  961.  
  962.         assert(status != STATUS_STOPPING);
  963.  
  964.         if (!(filesdone % 20))
  965.         {   SetGadgetAttrs
  966.             (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  967.                 FUELGAUGE_Level, filesfound + filesdone,
  968.                 TAG_END
  969.             );
  970.         }
  971.         filesdone++;
  972.  
  973.         if (!(FoundNodePtr = (struct FilesNode *) RemTail(&FoundList)))
  974.         {   rq("RemTail() failed (list is empty!)"); // should never happen
  975.         }
  976.         strcpy(activefile, FoundNodePtr->pathname);
  977.         length = strlen(activefile);
  978.         strcpy(datetime, FoundNodePtr->datetime);
  979.         strcpy(version,  FoundNodePtr->version );
  980.         strcpy(size,     FoundNodePtr->size    );
  981.         FreeMem(FoundNodePtr, sizeof(struct FilesNode));
  982.         // FilesNodePtr = NULL;
  983.  
  984.         strcpy(filename, files.basepath);
  985.         strcat(filename, activefile);
  986.  
  987.         if (files.mode == FILESMODE_BUILD)
  988.         {   strcpy(liststring[COLUMN_PATHNAME], " ");
  989.             strcat(liststring[COLUMN_PATHNAME], activefile);
  990.             strcpy(liststring[COLUMN_DATETIME], datetime);
  991.             strcpy(liststring[COLUMN_SIZE    ], size);
  992.             strcpy(liststring[COLUMN_VERSION ], version);
  993.             strcpy(liststring[COLUMN_SSDATETIME], "n/a");
  994.             strcpy(liststring[COLUMN_SSSIZE   ],  "n/a");
  995.             strcpy(liststring[COLUMN_SSVERSION],  "n/a");
  996.             dobuffer(4);
  997.         } else
  998.         {   // now we have removed the file from the list, and copied its
  999.             // name into activefile. Now we check it against each system
  1000.             // file.
  1001.             matched = FALSE;
  1002.  
  1003.             if ((SnapshotList.lh_Head)->ln_Succ) // if the list is non-empty
  1004.             {   for
  1005.                 (   SnapshotNodePtr = SnapshotList.lh_Head;
  1006.                     SnapshotNodePtr->Node.ln_Succ;
  1007.                     SnapshotNodePtr = SnapshotNodePtr->Node.ln_Succ
  1008.                 )
  1009.                 {   if (!matched && !(stricmp(activefile, SnapshotNodePtr->pathname)))
  1010.                     {   // we have a match
  1011.                         matched = TRUE;
  1012.                         SnapshotNodePtr->matched = (ABOOL) TRUE;
  1013.         
  1014.                         if (files.checkdatetime)
  1015.                         {   strcpy(liststring[COLUMN_DATETIME],   datetime);
  1016.                             strcpy(liststring[COLUMN_SSDATETIME], SnapshotNodePtr->datetime);
  1017.                         } else
  1018.                         {   strcpy(liststring[COLUMN_DATETIME],   "n/a");
  1019.                             strcpy(liststring[COLUMN_SSDATETIME], "n/a");
  1020.                         }                                                                
  1021.         
  1022.                         if (files.checksize)
  1023.                         {   strcpy(liststring[COLUMN_SIZE  ], size);
  1024.                             strcpy(liststring[COLUMN_SSSIZE], SnapshotNodePtr->size);
  1025.                         } else
  1026.                         {   strcpy(liststring[COLUMN_SIZE  ], "n/a");
  1027.                             strcpy(liststring[COLUMN_SSSIZE], "n/a");
  1028.                         }
  1029.  
  1030.                         if (files.checkversion)
  1031.                         {   strcpy(liststring[COLUMN_VERSION],   version);
  1032.                             strcpy(liststring[COLUMN_SSVERSION], SnapshotNodePtr->version);
  1033.                         } else
  1034.                         {   strcpy(liststring[COLUMN_VERSION  ], "n/a");
  1035.                             strcpy(liststring[COLUMN_SSVERSION], "n/a");
  1036.                         }
  1037.                         if
  1038.                         (   (files.checkdatetime && strcmp(SnapshotNodePtr->datetime, liststring[COLUMN_DATETIME]))
  1039.                          || (files.checkversion  && strcmp(SnapshotNodePtr->version,  liststring[COLUMN_VERSION ]))
  1040.                          || (files.checksize     && strcmp(SnapshotNodePtr->size,     liststring[COLUMN_SIZE    ]))
  1041.                         )
  1042.                         {   strcpy(liststring[COLUMN_PATHNAME], "!");
  1043.                             strcat(liststring[COLUMN_PATHNAME], activefile);
  1044.                             if (files.show[1])
  1045.                             {   dobuffer(1);
  1046.                         }   }
  1047.                         else
  1048.                         {   strcpy(liststring[COLUMN_PATHNAME], ".");
  1049.                             strcat(liststring[COLUMN_PATHNAME], activefile);
  1050.                             if (files.show[0])
  1051.                             {   dobuffer(0);
  1052.                         }   }
  1053.                         break;
  1054.             }   }   }
  1055.  
  1056.             if (files.show[2] && !matched) // third-party
  1057.             {   strcpy(liststring[COLUMN_PATHNAME], "+");
  1058.                 strcat(liststring[COLUMN_PATHNAME], activefile);
  1059.  
  1060.                 if (files.checkdatetime)
  1061.                 {   strcpy(liststring[COLUMN_DATETIME], datetime);
  1062.                 } else
  1063.                 {   strcpy(liststring[COLUMN_DATETIME], "?");
  1064.                 }
  1065.                 if (files.checkversion)
  1066.                 {   strcpy(liststring[COLUMN_VERSION], version);
  1067.                 } else
  1068.                 {   strcpy(liststring[COLUMN_VERSION], "?");
  1069.                 }
  1070.                 if (files.checksize)
  1071.                 {   strcpy(liststring[COLUMN_SIZE], size);
  1072.                 } else
  1073.                 {   strcpy(liststring[COLUMN_SIZE], "?");
  1074.                 }
  1075.  
  1076.                 strcpy(liststring[COLUMN_SSDATETIME], "n/a");
  1077.                 strcpy(liststring[COLUMN_SSVERSION ], "n/a");
  1078.                 strcpy(liststring[COLUMN_SSSIZE    ], "n/a");
  1079.                 dobuffer(2);
  1080.     }   }   }
  1081.  
  1082. /* 6. Decide missing files. ----------------------------------------------
  1083.  
  1084. Missing files can't be determined until we have looked through all the
  1085. found files. We go through the snapshot list looking at the `matched'
  1086. member variable. */
  1087.  
  1088.     if (files.mode == FILESMODE_COMPARE)
  1089.     {   // missing files
  1090.  
  1091.         if (status == STATUS_BUSY && files.show[3])
  1092.         {   SetGadgetAttrs
  1093.             (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  1094.                 FUELGAUGE_Min,   0,
  1095.                 FUELGAUGE_Max,   100,
  1096.                 FUELGAUGE_Level, 83,
  1097.                 GA_Text,         "Deciding missing...",
  1098.                 TAG_END
  1099.             );
  1100.  
  1101.             if ((SnapshotList.lh_Head)->ln_Succ) // if the list is non-empty
  1102.             {   for
  1103.                 (   SnapshotNodePtr = SnapshotList.lh_Head;
  1104.                     SnapshotNodePtr->Node.ln_Succ;
  1105.                     SnapshotNodePtr = SnapshotNodePtr->Node.ln_Succ
  1106.                 )
  1107.                 {   if (!(SnapshotNodePtr->matched))
  1108.                     {   strcpy(liststring[COLUMN_PATHNAME], "-");
  1109.                         strcat(liststring[COLUMN_PATHNAME], SnapshotNodePtr->pathname);
  1110.                         strcpy(liststring[COLUMN_VERSION ], "n/a");
  1111.                         strcpy(liststring[COLUMN_DATETIME], "n/a");
  1112.                         strcpy(liststring[COLUMN_SIZE    ], "n/a");
  1113.  
  1114.                         if (files.checkdatetime)
  1115.                         {    strcpy(liststring[COLUMN_SSDATETIME], SnapshotNodePtr->datetime);
  1116.                         } else
  1117.                         {    strcpy(liststring[COLUMN_SSDATETIME], "n/a");
  1118.                         }
  1119.                         if (files.checkversion)
  1120.                         {    strcpy(liststring[COLUMN_SSVERSION], SnapshotNodePtr->version);
  1121.                         } else
  1122.                         {    strcpy(liststring[COLUMN_SSVERSION], "n/a");
  1123.                         }
  1124.                         if (files.checksize)
  1125.                         {    strcpy(liststring[COLUMN_SSSIZE], SnapshotNodePtr->size);
  1126.                         } else
  1127.                         {    strcpy(liststring[COLUMN_SSSIZE], "n/a");
  1128.                         }
  1129.                         dobuffer(3);
  1130.     }   }   }   }   }
  1131.     if (TheHandle)
  1132.     {   Close(TheHandle); // Close() doesn't return an error code
  1133.         TheHandle = NULL;
  1134. }   }
  1135.  
  1136. MODULE void files_work(void)
  1137. {   BOOL                 more;      // BOOL, not ABOOL
  1138.     BPTR                 DirHandle; // = NULL;
  1139.     LONG                 ed;
  1140.     struct ExAllControl* eac;       // = NULL;
  1141.     struct ExAllData*    ead;
  1142.     struct DateTime      DateTime;
  1143.     ULONG                baselength    = strlen(files.basepath);
  1144.     TEXT                 datetime[18 + 1],
  1145.                          size[13 + 1];
  1146.  
  1147.     DateTime.dat_Format  = FORMAT_CDN;
  1148.     DateTime.dat_Flags   = NULL;
  1149.     DateTime.dat_StrDay  = NULL;
  1150.     DateTime.dat_StrDate = datestring;
  1151.     DateTime.dat_StrTime = timestring;
  1152.  
  1153.     /* Service routine for stage1(). Each call of this routine
  1154.     handles one directory from the work stack. This routine is the one
  1155.     that actually makes the DOS calls. It pushes any subdirectories
  1156.     found onto the stack.
  1157.  
  1158.     lockstring contains the pathname of the directory to examine
  1159.         (with base path).
  1160.     activedir contains the pathname of the directory to examine
  1161.         (without base path).
  1162.     activefile will contain the pathname of each file/dir found
  1163.         (with base path). */
  1164.  
  1165.     strcpy(lockstring, files.basepath);
  1166.     strcat(lockstring, activedir);
  1167.  
  1168.     if (!(DirHandle = (BPTR) Lock(lockstring, ACCESS_READ)))
  1169.     {   // Printf("Can't lock %s!\n", lockstring);
  1170.         rq("Can't lock directory!");
  1171.     }
  1172.     if (!(eac = AllocDosObject(DOS_EXALLCONTROL, NULL)))
  1173.     {   UnLock(DirHandle);
  1174.         DirHandle = NULL;
  1175.         rq("Can't allocate DOS object!");
  1176.     }
  1177.  
  1178.     if (files.mode == FILESMODE_BUILD || files.checkdatetime)
  1179.     {   ed = ED_DATE; // we want name, type, size and date
  1180.     } elif (files.checksize)
  1181.     {   ed = ED_SIZE; // we want name, type and size
  1182.     } else
  1183.     {   ed = ED_TYPE; // we want name and type
  1184.     }
  1185.     eac->eac_LastKey = 0;
  1186.     do
  1187.     {   more = ExAll(DirHandle, (struct ExAllData *) EADataPtr, 4096, ed, eac);
  1188.         if (!more && IoErr() != ERROR_NO_MORE_ENTRIES)
  1189.         {   FreeDosObject(DOS_EXALLCONTROL, eac);
  1190.             eac = NULL;
  1191.             UnLock(DirHandle);
  1192.             DirHandle = NULL;
  1193.             rq("Can't examine path!"); /* ExAll() failed abnormally */
  1194.         }
  1195.         if (eac->eac_Entries == 0)
  1196.         {   ; /* ExAll() failed normally with no entries */
  1197.             continue; /* more is USUALLY zero */
  1198.         }
  1199.         ead = (struct ExAllData *) EADataPtr;
  1200.  
  1201.         do
  1202.         {   /* use ead here */
  1203.  
  1204.             strcpy(activefile, lockstring);
  1205.             if (!AddPart(activefile, ead->ed_Name, PATHNAMEFIELD))
  1206.             {   FreeDosObject(DOS_EXALLCONTROL, eac);
  1207.                 eac = NULL;
  1208.                 UnLock(DirHandle);
  1209.                 DirHandle = NULL;
  1210.                 rq("Can't add filename/dirname to path!");
  1211.             }
  1212.             if (ead->ed_Type == 2)
  1213.             // +2 is dir, +3 is softlink (not yet supported), -3 is file
  1214.             {   AddNameToTail(&DirList, &activefile[baselength]);
  1215.             } elif (ead->ed_Type == -3) // if it's a file
  1216.             {   if (files.mode == FILESMODE_BUILD || files.checkdatetime)
  1217.                 {   DateTime.dat_Stamp.ds_Days   = ead->ed_Days;
  1218.                     DateTime.dat_Stamp.ds_Minute = ead->ed_Mins;
  1219.                     DateTime.dat_Stamp.ds_Tick   = ead->ed_Ticks;
  1220.                     DateToStr(&DateTime);
  1221.                     strcpy(datetime, timestring);
  1222.                     strcat(datetime, " ");
  1223.                     strcat(datetime, datestring);
  1224.                 } else
  1225.                 {   strcpy(datetime, "n/a");
  1226.                 }
  1227.                 if (files.mode == FILESMODE_BUILD || files.checksize)
  1228.                 {   comma(ead->ed_Size, size);
  1229.                 } else
  1230.                 {   strcpy(size, "n/a");
  1231.                 }
  1232.                 AddFilesNode
  1233.                 (   &FoundList,
  1234.                     &activefile[baselength],
  1235.                     datetime,
  1236.                     "",
  1237.                     size
  1238.                 ); 
  1239.  
  1240.                 filesfound++;
  1241.             }
  1242.  
  1243.             /* get next ead */
  1244.             ead = ead->ed_Next;
  1245.         } while(ead);
  1246.     } while(more);
  1247.  
  1248.     FreeDosObject(DOS_EXALLCONTROL, eac);
  1249.     // eac = NULL;
  1250.     UnLock(DirHandle);
  1251.     // DirHandle = NULL;
  1252. }
  1253.  
  1254. MODULE void dobuffer(ULONG whichpen)
  1255. {   struct Node* ListBrowserNodePtr;
  1256.     TEXT         codestring[512 + 1], // codestrings are sometimes longer than 256 chacters
  1257.                  spaces[LONGFIELD + 1];
  1258.     SLONG        gap;
  1259.     ULONG        i;
  1260.  
  1261.     /* Service routine for stage2(). */
  1262.  
  1263.     if (!(ListBrowserNodePtr = AllocListBrowserNode
  1264.     (   7,              // columns,
  1265.         LBNA_Column,    0,
  1266.             LBNA_Flags,     LBFLG_CUSTOMPENS,
  1267.             LBNCA_FGPen,    BLACK,
  1268.             LBNCA_BGPen,    penn[whichpen].pennumber,
  1269.             LBNCA_CopyText, TRUE,
  1270.             LBNCA_Text,     &liststring[0][1],
  1271.         LBNA_Column,    1,
  1272.             LBNA_Flags,     LBFLG_CUSTOMPENS,
  1273.             LBNCA_FGPen,    BLACK,
  1274.             LBNCA_BGPen,    penn[whichpen].pennumber,
  1275.             LBNCA_CopyText, TRUE,
  1276.             LBNCA_Text,     liststring[1],
  1277.         LBNA_Column,    2,
  1278.             LBNA_Flags,     LBFLG_CUSTOMPENS,
  1279.             LBNCA_FGPen,    BLACK,
  1280.             LBNCA_BGPen,    penn[whichpen].pennumber,
  1281.             LBNCA_CopyText, TRUE,
  1282.             LBNCA_Text,     liststring[2],
  1283.         LBNA_Column,    3,
  1284.             LBNA_Flags,     LBFLG_CUSTOMPENS,
  1285.             LBNCA_FGPen,    BLACK,
  1286.             LBNCA_BGPen,    penn[whichpen].pennumber,
  1287.             LBNCA_CopyText, TRUE,
  1288.             LBNCA_Text,     liststring[3],
  1289.         LBNA_Column,    4,
  1290.             LBNA_Flags,     LBFLG_CUSTOMPENS,
  1291.             LBNCA_FGPen,    BLACK,
  1292.             LBNCA_BGPen,    penn[whichpen].pennumber,
  1293.             LBNCA_CopyText, TRUE,
  1294.             LBNCA_Text,     liststring[4],
  1295.         LBNA_Column,    5,
  1296.             LBNA_Flags,     LBFLG_CUSTOMPENS,
  1297.             LBNCA_FGPen,    BLACK,
  1298.             LBNCA_BGPen,    penn[whichpen].pennumber,
  1299.             LBNCA_CopyText, TRUE,
  1300.             LBNCA_Text,     liststring[5],
  1301.         LBNA_Column,    6,
  1302.             LBNA_Flags,     LBFLG_CUSTOMPENS,
  1303.             LBNCA_FGPen,    BLACK,
  1304.             LBNCA_BGPen,    penn[whichpen].pennumber,
  1305.             LBNCA_CopyText, TRUE,
  1306.             LBNCA_Text,     liststring[6],
  1307.     TAG_END)))
  1308.     {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  1309.     }
  1310.     AddTail(&ResultList, ListBrowserNodePtr); // AddTail() has no return code
  1311.  
  1312.     if (files.mode == FILESMODE_BUILD)
  1313.     {   strcpy(codestring, &liststring[COLUMN_PATHNAME][1]);
  1314.         strcat(codestring, "\n");
  1315.         strcat(codestring, liststring[COLUMN_DATETIME]);
  1316.         strcat(codestring, "\n");
  1317.         strcat(codestring, liststring[COLUMN_VERSION]);
  1318.         strcat(codestring, "\n");
  1319.         strcat(codestring, liststring[COLUMN_SIZE   ]);
  1320.         strcat(codestring, "\n");
  1321.  
  1322.         if (Write(TheHandle, codestring, strlen(codestring)) != strlen(codestring))
  1323.         {   rq("Can't write to snapshot file!");
  1324.     }   }
  1325.     else
  1326.     {   assert(files.mode == FILESMODE_COMPARE);
  1327.         if (files.log)
  1328.         {   strcpy(codestring, liststring[COLUMN_PATHNAME]);
  1329.             if (strlen(liststring[COLUMN_PATHNAME]) >= 35)
  1330.             {   strcat(codestring, "\n"
  1331.                 "                                    "); // 36 spaces
  1332.             } else
  1333.             {   gap = 36 - strlen(liststring[COLUMN_PATHNAME]);
  1334.                 for (i = 0; i < gap; i++)
  1335.                 {   spaces[i] = ' ';
  1336.                 }
  1337.                 spaces[gap] = 0;
  1338.                 strcat(codestring, spaces);
  1339.             }
  1340.             if (!(strcmp(liststring[COLUMN_SIZE], "n/a")))
  1341.             {   strcat(codestring, "          n/a "); // 10 spaces
  1342.             } else
  1343.             {   strcat(codestring, liststring[COLUMN_SIZE    ]);
  1344.                 gap = 14 - strlen(liststring[COLUMN_SIZE     ]);
  1345.                 if (gap >= 1)
  1346.                 {   for (i = 0; i < gap; i++)
  1347.                     {   spaces[i] = ' ';
  1348.                     }
  1349.                     spaces[gap] = 0;
  1350.                     strcat(codestring, spaces);
  1351.             }   }
  1352.  
  1353.             strcat(codestring, liststring[COLUMN_DATETIME]);
  1354.             gap = 18 - strlen(liststring[COLUMN_DATETIME]);
  1355.             if (gap >= 1)
  1356.             {   for (i = 0; i < gap; i++)
  1357.                 {   spaces[i] = ' ';
  1358.                 }
  1359.                 spaces[gap] = 0;
  1360.                 strcat(codestring, spaces);
  1361.             }                                    
  1362.             strcat(codestring, liststring[COLUMN_VERSION]);
  1363.             strcat(codestring, "\n"
  1364.             "                                    "); // 36 spaces
  1365.             if (!(strcmp(liststring[COLUMN_SSSIZE], "n/a")))
  1366.             {   strcat(codestring, "          n/a "); // 10 spaces
  1367.             } else
  1368.             {   strcat(codestring, liststring[COLUMN_SSSIZE    ]);
  1369.                 gap = 14 - strlen(liststring[COLUMN_SSSIZE    ]);
  1370.                 if (gap >= 1)
  1371.                 {   for (i = 0; i < gap; i++)
  1372.                     {   spaces[i] = ' ';
  1373.                     }
  1374.                     spaces[gap] = 0;
  1375.                     strcat(codestring, spaces);
  1376.             }   }
  1377.             strcat(codestring, liststring[COLUMN_SSDATETIME]);
  1378.             gap = 18 - strlen(liststring[COLUMN_SSDATETIME]);
  1379.             if (gap >= 1)
  1380.             {   for (i = 0; i < gap; i++)
  1381.                 {   spaces[i] = ' ';
  1382.                 }
  1383.                 spaces[gap] = 0;
  1384.                 strcat(codestring, spaces);
  1385.             }
  1386.             strcat(codestring, liststring[COLUMN_SSVERSION]);
  1387.             strcat(codestring, "\n");
  1388.  
  1389.             if (Write(TheHandle, codestring, strlen(codestring)) != strlen(codestring))
  1390.             {   rq("Can't append to logfile!");
  1391. }   }   }   }
  1392.  
  1393. AGLOBAL void files_init(void)
  1394. {   ULONG        i;
  1395.     struct Node* ListBrowserNodePtr;
  1396.  
  1397.     lockscreen();
  1398.     for (i = 0; i <= 4; i++)
  1399.     {   penn[i].pennumber = FindColor
  1400.         (   ScreenPtr->ViewPort.ColorMap,
  1401.             penn[i].red,
  1402.             penn[i].green,
  1403.             penn[i].blue,
  1404.             -1
  1405.         );
  1406.     }
  1407.     unlockscreen();
  1408.  
  1409.     NewList(&DirList);
  1410.     NewList(&FoundList);
  1411.     NewList(&SnapshotList);
  1412.     NewList(&ResultList);
  1413.     NewList(&EmptyResultList);
  1414.  
  1415.     /* Create a 7-column listbrowser list with only one node containing
  1416.     only column tags. */
  1417.     if (!(ListBrowserNodePtr = AllocListBrowserNode
  1418.     (   7,           // columns
  1419.         /* LBNCA_ tags are those that apply to the specific column. */
  1420.         LBNA_Column, 0,
  1421.         LBNA_Column, 1,
  1422.         LBNA_Column, 2,
  1423.         LBNA_Column, 3,
  1424.         LBNA_Column, 4,
  1425.         LBNA_Column, 5,
  1426.         LBNA_Column, 6,
  1427.         TAG_END
  1428.     )))
  1429.     {   rq("Can't create ReAction listbrowser.gadget node(s)!");
  1430.     }
  1431.     AddTail(&EmptyResultList, ListBrowserNodePtr); // AddTail() has no return code
  1432. }
  1433.  
  1434. AGLOBAL void files_exit(void)
  1435. {   // The window should be closed before calling this.
  1436.     if ((ResultList.lh_Head)->ln_Succ) // if the list is non-empty
  1437.     {   clearreactionlist(&ResultList);
  1438.     }
  1439.     if ((DirList.lh_Head)->ln_Succ) // if the list is non-empty
  1440.     {   FreeNameNodes(&DirList);
  1441.     }
  1442.     if ((FoundList.lh_Head)->ln_Succ) // if the list is non-empty
  1443.     {   FreeFilesNodes(&FoundList);
  1444.     }
  1445.     if ((SnapshotList.lh_Head)->ln_Succ) // if the list is non-empty
  1446.     {   FreeFilesNodes(&SnapshotList);
  1447.     }
  1448.     if (TheHandle)
  1449.     {   Close(TheHandle); // Close() doesn't return an error code
  1450.         TheHandle = NULL;
  1451.     }
  1452. }
  1453. AGLOBAL void files_die(void)
  1454. {   ULONG i;
  1455.  
  1456.     if ((EmptyResultList.lh_Head)->ln_Succ) // if the list is non-empty
  1457.     {   clearreactionlist(&EmptyResultList);
  1458.     }
  1459.  
  1460.     IOBuffer[23] = (UBYTE) files.log;
  1461.     for (i = 0; i <= 3; i++)
  1462.     {   IOBuffer[i + 8] = (UBYTE) files.show[i];
  1463.     }
  1464.     IOBuffer[7]  = (UBYTE) files.checkversion;
  1465.     IOBuffer[12] = (UBYTE) files.checkdatetime;
  1466.     IOBuffer[13] = (UBYTE) files.mode;
  1467.     IOBuffer[14] = (UBYTE) files.checksize;
  1468. }
  1469.  
  1470. AGLOBAL void files_config(void)
  1471. {   UBYTE i;
  1472.  
  1473.     files.log = (ULONG) IOBuffer[23];
  1474.     for (i = 0; i <= 3; i++)
  1475.     {   files.show[i] = (ULONG) IOBuffer[i + 8];
  1476.     }
  1477.     files.checkversion  = (ULONG) IOBuffer[7];
  1478.     files.checkdatetime = (ULONG) IOBuffer[12];
  1479.     files.mode          = (UWORD) IOBuffer[13];
  1480.     files.checksize     = (ULONG) IOBuffer[14];
  1481. }
  1482.  
  1483. AGLOBAL void files_loop(ULONG gid)
  1484. {   STRPTR stringptr;
  1485.  
  1486.     switch (gid)
  1487.     {
  1488.     case GID_10_RA1:
  1489.         if (!(GetAttr
  1490.         (   RADIOBUTTON_Selected, files_gadgets[GID_10_RA1], (ULONG *) &files.mode
  1491.         )))
  1492.         {   rq("Unsupported inquiry!"); // should never happen
  1493.         }
  1494.         files_updatelog();
  1495.     break;
  1496.     case GID_10_CB1:
  1497.         if (!(GetAttr
  1498.         (   GA_Selected, files_gadgets[GID_10_CB1], (ULONG *) &files.show[0]
  1499.         )))
  1500.         {   rq("Unsupported inquiry!"); // should never happen
  1501.         }
  1502.     break;
  1503.     case GID_10_CB2:
  1504.         if (!(GetAttr
  1505.         (   GA_Selected, files_gadgets[GID_10_CB2], (ULONG *) &(files.show[1])
  1506.         )))
  1507.         {   rq("Unsupported inquiry!"); // should never happen
  1508.         }
  1509.     break;
  1510.     case GID_10_CB3:
  1511.         if (!(GetAttr
  1512.         (   GA_Selected, files_gadgets[GID_10_CB3], (ULONG *) &files.show[2]
  1513.         )))
  1514.         {   rq("Unsupported inquiry!"); // should never happen
  1515.         }
  1516.     break;
  1517.     case GID_10_CB4:
  1518.         if (!(GetAttr
  1519.         (   GA_Selected, files_gadgets[GID_10_CB4], (ULONG *) &files.show[3]
  1520.         )))                                                                    
  1521.         {   rq("Unsupported inquiry!"); // should never happen
  1522.         }
  1523.     break;
  1524.     case GID_10_CB5:
  1525.         if (!(GetAttr
  1526.         (   GA_Selected, files_gadgets[GID_10_CB5], (ULONG *) &files.checkversion
  1527.         )))                                                                    
  1528.         {   rq("Unsupported inquiry!"); // should never happen
  1529.         }
  1530.     break;
  1531.     case GID_10_CB6:
  1532.         if (!(GetAttr
  1533.         (   GA_Selected, files_gadgets[GID_10_CB6], (ULONG *) &files.checkdatetime
  1534.         )))                                                                    
  1535.         {   rq("Unsupported inquiry!"); // should never happen
  1536.         }
  1537.     break;
  1538.     case GID_10_CB7:
  1539.         if (!(GetAttr
  1540.         (   GA_Selected, files_gadgets[GID_10_CB7], &files.log
  1541.         )))
  1542.         {   rq("Unsupported inquiry!"); // should never happen
  1543.         }
  1544.         files_updatelog();
  1545.         if (files.log)
  1546.         {   ActivateLayoutGadget(files_gadgets[GID_10_LY1], MainWindowPtr, NULL, (Object) files_gadgets[GID_10_ST1]);
  1547.         }
  1548.     break;
  1549.     case GID_10_CB8:
  1550.         if (!(GetAttr
  1551.         (   GA_Selected, files_gadgets[GID_10_CB8], (ULONG *) &files.checksize
  1552.         )))
  1553.         {   rq("Unsupported inquiry!"); // should never happen
  1554.         }
  1555.     break;
  1556.     case GID_10_ST1:
  1557.         if (!(GetAttr
  1558.         (   STRINGA_TextVal, files_gadgets[GID_10_ST1], (ULONG *) &stringptr
  1559.         )))
  1560.         {   rq("Unsupported inquiry!"); // should never happen
  1561.         }
  1562.         strcpy(files.logfile, stringptr);
  1563.     break;
  1564.     case GID_10_ST2:
  1565.         if (!(GetAttr
  1566.         (   STRINGA_TextVal, files_gadgets[GID_10_ST2], (ULONG *) &stringptr
  1567.         )))
  1568.         {   rq("Unsupported inquiry!"); // should never happen
  1569.         }
  1570.         strcpy(files.snapshot, stringptr);
  1571.     break;
  1572.     case GID_10_ST3:
  1573.         if (!(GetAttr
  1574.         (   STRINGA_TextVal, files_gadgets[GID_10_ST3], (ULONG *) &stringptr
  1575.         )))
  1576.         {   rq("Unsupported inquiry!"); // should never happen
  1577.         }
  1578.         strcpy(files.basepath, stringptr);
  1579.         addslash();
  1580.     break;
  1581.     case GID_10_BU1:
  1582.         if (asl("#?.log"))
  1583.         {   strcpy(files.logfile, aslresult);
  1584.             SetGadgetAttrs
  1585.             (   files_gadgets[GID_10_ST1], MainWindowPtr, NULL,
  1586.                 STRINGA_TextVal, files.logfile,
  1587.                 TAG_END
  1588.            );
  1589.         }
  1590.     break;
  1591.     case GID_10_BU2:
  1592.         updatefiles();
  1593.     break;
  1594.     case GID_10_BU4:
  1595.         if (asl("#?.snapshot"))
  1596.         {   strcpy(files.snapshot, aslresult);
  1597.             SetGadgetAttrs
  1598.             (   files_gadgets[GID_10_ST2], MainWindowPtr, NULL,
  1599.                 STRINGA_TextVal, files.snapshot,
  1600.                 TAG_END
  1601.             );
  1602.         }
  1603.     break;
  1604.     case GID_10_BU5:
  1605.         if (dirasl())
  1606.         {   strcpy(files.basepath, aslresult);
  1607.             SetGadgetAttrs
  1608.             (   files_gadgets[GID_10_ST3], MainWindowPtr, NULL,
  1609.                 STRINGA_TextVal, files.basepath,
  1610.                 TAG_END
  1611.             );
  1612.             addslash();
  1613.         }
  1614.     break;
  1615.     default:
  1616.     break;
  1617. }   }
  1618.  
  1619. AGLOBAL ULONG Hook10Func(struct Hook *h, VOID *o, VOID *msg)
  1620. {   /* "When the hook is called, the data argument points to the 
  1621.     window object and message argument to the IntuiMessage." */
  1622.  
  1623.     UWORD code, qual;
  1624.     ULONG scroll = 0;
  1625.  
  1626.     geta4(); // wait till here before doing anything
  1627.  
  1628.     code = ((struct IntuiMessage *) msg)->Code;
  1629.     qual = ((struct IntuiMessage *) msg)->Qualifier;
  1630.  
  1631.     switch(code)
  1632.     {
  1633.     case SCAN_HELP:
  1634.         if (status == STATUS_READY)
  1635.         {   helpabout();
  1636.         }
  1637.     break;
  1638.     case SCAN_ESCAPE:
  1639.         if (status == STATUS_READY)
  1640.         {   if ((qual & IEQUALIFIER_LSHIFT) || (qual & IEQUALIFIER_RSHIFT))
  1641.             {   cleanexit(EXIT_SUCCESS);
  1642.             } else page = 0;
  1643.         } else
  1644.         {   assert(status == STATUS_BUSY);
  1645.             status = STATUS_STOPPING;
  1646.         }
  1647.     break;
  1648.     case SCAN_PERIOD:
  1649.         if (asl("#?.log"))
  1650.         {   strcpy(files.logfile, aslresult);
  1651.             SetGadgetAttrs
  1652.             (   files_gadgets[GID_10_ST1], MainWindowPtr, NULL,
  1653.                 STRINGA_TextVal, files.logfile,
  1654.                 TAG_END
  1655.            );
  1656.         }
  1657.     break;
  1658.     case SCAN_E:
  1659.         if (files.mode == 0)
  1660.         {   files.mode = 1;
  1661.         } else
  1662.         {   files.mode = 0;
  1663.         }
  1664.         SetGadgetAttrs
  1665.         (   files_gadgets[GID_10_RA1], MainWindowPtr, NULL,
  1666.             RADIOBUTTON_Selected, files.mode,
  1667.         TAG_END);
  1668.         // we must explicitly refresh
  1669.         RefreshGadgets((struct Gadget *) files_gadgets[GID_10_RA1], MainWindowPtr, NULL);
  1670.         files_updatelog();
  1671.     break;
  1672.     case SCAN_S:
  1673.         ActivateLayoutGadget(files_gadgets[GID_10_LY1], MainWindowPtr, NULL, (Object) files_gadgets[GID_10_ST2]);
  1674.     break;
  1675.     case SCAN_B:
  1676.         ActivateLayoutGadget(files_gadgets[GID_10_LY1], MainWindowPtr, NULL, (Object) files_gadgets[GID_10_ST3]);
  1677.     break;
  1678.     case SCAN_UP:
  1679.         if (qual & IEQUALIFIER_CONTROL)
  1680.         {   scroll = LBP_TOP;
  1681.         } elif (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  1682.         {   scroll = LBP_PAGEUP;
  1683.         } else scroll = LBP_LINEUP;
  1684.     break;
  1685.     case SCAN_DOWN:
  1686.         if (qual & IEQUALIFIER_CONTROL)
  1687.         {   scroll = LBP_BOTTOM;
  1688.         } elif (qual & IEQUALIFIER_LSHIFT || qual & IEQUALIFIER_RSHIFT)
  1689.         {   scroll = LBP_PAGEDOWN;
  1690.         } else scroll = LBP_LINEDOWN;
  1691.     break;
  1692.     default:
  1693.     break;
  1694.     }
  1695.  
  1696.     if (code == SCAN_UP || code == SCAN_DOWN)
  1697.     {   SetGadgetAttrs
  1698.         (   files_gadgets[GID_10_LB1],    // pointer to gadget
  1699.             MainWindowPtr,                // pointer to window (not window object!)
  1700.             NULL,                         // pointer to requester
  1701.             LISTBROWSER_Position, scroll, // tags
  1702.             TAG_DONE                      // done
  1703.         );
  1704.     }
  1705.  
  1706.     return(1);
  1707. }
  1708.  
  1709. MODULE void stopping(STRPTR status)
  1710. {   SetGadgetAttrs
  1711.     (   files_gadgets[GID_10_FG1], MainWindowPtr, NULL,
  1712.         GA_Text, status,
  1713.         TAG_END
  1714.     );
  1715.     SetGadgetAttrs // `Stop'
  1716.     (   files_gadgets[GID_10_BU3], MainWindowPtr, NULL,
  1717.         GA_Disabled, TRUE,
  1718.         TAG_END
  1719.     );
  1720. }
  1721.  
  1722. MODULE void files_updatelog(void)
  1723. {   ULONG i;
  1724.  
  1725.     updateghosting();
  1726.  
  1727.     SetGadgetAttrs // `Log to file:' (string)
  1728.     (   files_gadgets[GID_10_ST1], MainWindowPtr, NULL,
  1729.         GA_Disabled, innerghost,
  1730.         TAG_END
  1731.     );
  1732.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_ST1], MainWindowPtr, NULL);
  1733.  
  1734.     SetGadgetAttrs // `Log to file:' (ASL button)
  1735.     (   files_gadgets[GID_10_BU1], MainWindowPtr, NULL,
  1736.         GA_Disabled, innerghost,
  1737.         TAG_END
  1738.     );
  1739.     // buttons can autorefresh
  1740.  
  1741.     SetGadgetAttrs
  1742.     (   files_gadgets[GID_10_CB5], MainWindowPtr, NULL,
  1743.         GA_Disabled, outerghost,
  1744.     TAG_END);
  1745.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB5], MainWindowPtr, NULL);
  1746.  
  1747.     SetGadgetAttrs
  1748.     (   files_gadgets[GID_10_CB6], MainWindowPtr, NULL,
  1749.         GA_Disabled, outerghost,
  1750.     TAG_END);
  1751.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB6], MainWindowPtr, NULL);
  1752.  
  1753.     SetGadgetAttrs
  1754.     (   files_gadgets[GID_10_CB7], MainWindowPtr, NULL,
  1755.         GA_Disabled, outerghost,
  1756.     TAG_END);
  1757.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB7], MainWindowPtr, NULL);
  1758.  
  1759.     SetGadgetAttrs
  1760.     (   files_gadgets[GID_10_CB8], MainWindowPtr, NULL,
  1761.         GA_Disabled, outerghost,
  1762.     TAG_END);
  1763.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB8], MainWindowPtr, NULL);
  1764.  
  1765.     for (i = 0; i <= 3; i++)
  1766.     {   SetGadgetAttrs
  1767.         (   files_gadgets[GID_10_CB1 + i], MainWindowPtr, NULL,
  1768.             GA_Disabled, outerghost,
  1769.         TAG_END);
  1770.         RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB1 + i], MainWindowPtr, NULL);
  1771. }   }
  1772.  
  1773. MODULE void updateghosting(void)
  1774. {   /* Decides whether certain gadgets should be ghosted or not, and
  1775.     sets variables accordingly. */
  1776.  
  1777.     if (files.mode == FILESMODE_COMPARE)
  1778.     {   outerghost = FALSE;
  1779.         if (files.log)
  1780.         {   innerghost = FALSE;
  1781.         } else
  1782.         {   innerghost = TRUE;
  1783.     }   }
  1784.     else
  1785.     {   assert(files.mode == FILESMODE_BUILD);
  1786.         outerghost =
  1787.         innerghost = TRUE;
  1788. }   }
  1789.  
  1790. MODULE void gadgetstate(ABOOL starting)
  1791. {   /* If starting is TRUE,  we are starting the operation.
  1792.        If starting is FALSE, we are   ending the operation. */
  1793.  
  1794.     BOOL  innerstate, outerstate, inverse;
  1795.     ULONG i;
  1796.  
  1797.     if (starting)
  1798.     {   innerstate =
  1799.         outerstate = starting;
  1800.         inverse    = FALSE;
  1801.     } else
  1802.     {   innerstate = innerghost;
  1803.         outerstate = outerghost;
  1804.         inverse    = TRUE;
  1805.     }
  1806.  
  1807.     // Disabled during operation, enabled otherwise ----------------------
  1808.  
  1809.     SetGadgetAttrs // `Update'
  1810.     (   files_gadgets[GID_10_BU2], MainWindowPtr, NULL,
  1811.         GA_Disabled, starting,
  1812.         TAG_END
  1813.     );
  1814.     // buttons can autorefresh
  1815.  
  1816.     SetGadgetAttrs
  1817.     (   files_gadgets[GID_10_ST2], MainWindowPtr, NULL,
  1818.         GA_Disabled, starting,
  1819.         TAG_END
  1820.     );
  1821.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_ST2], MainWindowPtr, NULL);
  1822.  
  1823.     SetGadgetAttrs
  1824.     (   files_gadgets[GID_10_ST3], MainWindowPtr, NULL,
  1825.         GA_Disabled, starting,
  1826.         TAG_END
  1827.     );
  1828.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_ST3], MainWindowPtr, NULL);
  1829.  
  1830.     SetGadgetAttrs
  1831.     (   files_gadgets[GID_10_BU4], MainWindowPtr, NULL,
  1832.         GA_Disabled, starting,
  1833.         TAG_END
  1834.     );
  1835.     // buttons can autorefresh
  1836.  
  1837.     SetGadgetAttrs
  1838.     (   files_gadgets[GID_10_BU5], MainWindowPtr, NULL,
  1839.         GA_Disabled, starting,
  1840.         TAG_END
  1841.     );
  1842.     // buttons can autorefresh
  1843.  
  1844.     /* This should work but seems not to :-(
  1845.     SetGadgetAttrs
  1846.     (   files_gadgets[GID_10_RA1], MainWindowPtr, NULL,
  1847.         GA_Disabled, starting,
  1848.         TAG_END
  1849.     );
  1850.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_RA1], MainWindowPtr, NULL); */
  1851.  
  1852.     // Enabled during operation, disabled otherwise ----------------------
  1853.  
  1854.     SetGadgetAttrs // `Stop'
  1855.     (   files_gadgets[GID_10_BU3], MainWindowPtr, NULL,
  1856.         GA_Disabled, inverse,
  1857.         TAG_END
  1858.     );
  1859.     // buttons can autorefresh
  1860.  
  1861.     // Disabled during operation and/or in build-mode --------------------
  1862.  
  1863.     for (i = 0; i <= 3; i++)
  1864.     {   SetGadgetAttrs
  1865.         (   files_gadgets[GID_10_CB1 + i], MainWindowPtr, NULL,
  1866.             GA_Disabled, outerstate,
  1867.             TAG_END
  1868.         );
  1869.         RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB1 + i], MainWindowPtr, NULL);
  1870.     }
  1871.  
  1872.     SetGadgetAttrs
  1873.     (   files_gadgets[GID_10_CB5], MainWindowPtr, NULL,
  1874.         GA_Disabled, outerstate,
  1875.         TAG_END
  1876.     );
  1877.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB5], MainWindowPtr, NULL);
  1878.  
  1879.     SetGadgetAttrs
  1880.     (   files_gadgets[GID_10_CB6], MainWindowPtr, NULL,
  1881.         GA_Disabled, outerstate,
  1882.         TAG_END
  1883.     );
  1884.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB6], MainWindowPtr, NULL);
  1885.  
  1886.     SetGadgetAttrs
  1887.     (   files_gadgets[GID_10_CB7], MainWindowPtr, NULL,
  1888.         GA_Disabled, outerstate,
  1889.         TAG_END
  1890.     );
  1891.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB7], MainWindowPtr, NULL);
  1892.  
  1893.     SetGadgetAttrs
  1894.     (   files_gadgets[GID_10_CB8], MainWindowPtr, NULL,
  1895.         GA_Disabled, outerstate,
  1896.         TAG_END
  1897.     );
  1898.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_CB8], MainWindowPtr, NULL);
  1899.  
  1900.     // Disabled during operation and/or in build-mode and/or without
  1901.     // logging -----------------------------------------------------------
  1902.  
  1903.     SetGadgetAttrs // `Log to file:' (string)
  1904.     (   files_gadgets[GID_10_ST1], MainWindowPtr, NULL,
  1905.         GA_Disabled, innerstate,
  1906.         TAG_END
  1907.     );
  1908.     RefreshGadgets((struct Gadget *) files_gadgets[GID_10_ST1], MainWindowPtr, NULL);
  1909.  
  1910.     SetGadgetAttrs // `Log to file:' (ASL button)
  1911.     (   files_gadgets[GID_10_BU1], MainWindowPtr, NULL,
  1912.         GA_Disabled, innerstate,
  1913.         TAG_END
  1914.     );
  1915.     // buttons can autorefresh
  1916. }
  1917.  
  1918. MODULE void AddFilesNode(struct List* ListPtr, STRPTR pathname, STRPTR datetime, STRPTR version, STRPTR size)
  1919. {   struct FilesNode* FilesNodePtr;
  1920.  
  1921.     if (!(FilesNodePtr = AllocMem(sizeof(struct FilesNode), MEMF_CLEAR)))
  1922.         rq("Out of memory!");
  1923.     strcpy(FilesNodePtr->pathname, pathname);
  1924.     strcpy(FilesNodePtr->datetime, datetime);
  1925.     strcpy(FilesNodePtr->version,  version );
  1926.     strcpy(FilesNodePtr->size,     size    );
  1927.     FilesNodePtr->matched      = FALSE;
  1928.     FilesNodePtr->Node.ln_Name = NULL;
  1929.     FilesNodePtr->Node.ln_Type = NT_USER;
  1930.     FilesNodePtr->Node.ln_Pri  = 0;
  1931.     AddTail((struct List *) ListPtr, (struct Node *) FilesNodePtr);
  1932. }
  1933.  
  1934. MODULE void FreeFilesNodes(struct List* ListPtr)
  1935. {   /* RKM Libraries, p. 496:
  1936.     
  1937.     "Free the entire list, including the header. The header is not
  1938.     updated as the list is freed. This function demonstrates how to
  1939.     avoid referencing freed memory when deallocating nodes." */
  1940.  
  1941.     struct FilesNode *WorkNodePtr, *NextNodePtr;
  1942.     
  1943.     WorkNodePtr = (struct FilesNode *) (ListPtr->lh_Head); /* first node */
  1944.     while (NextNodePtr = (struct FilesNode *) (WorkNodePtr->Node.ln_Succ))
  1945.     {   FreeMem(WorkNodePtr, sizeof(struct FilesNode));
  1946.         WorkNodePtr = NextNodePtr;
  1947.     }
  1948.     NewList(ListPtr);
  1949. }
  1950. MODULE void addslash(void)
  1951. {   ULONG length;
  1952.  
  1953.     length = strlen(files.basepath);
  1954.  
  1955.     if (length)
  1956.     {   if
  1957.         (   files.basepath[length - 1] != '/'
  1958.          && files.basepath[length - 1] != ':'
  1959.         )
  1960.         {   strcat(files.basepath, "/");
  1961.             SetGadgetAttrs
  1962.             (   files_gadgets[GID_10_ST3], MainWindowPtr, NULL,
  1963.                 STRINGA_TextVal, files.basepath,
  1964.                 TAG_END
  1965.             );
  1966. }   }   }
  1967.